#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/list.h>
#include <linux/printk.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/spinlock.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>

static dev_t tlc5615_devid;                  
static struct cdev tlc5615_cdev;           
static struct class *tlc5615_class = NULL;         
static struct device *tlc5615_device = NULL;
static int tlc5615_major = 0;
static int tlc5615_minor = 0;
static struct spi_device *tlc5615_spi = NULL;


static int tlc5615_spi_read(void)
{
    int status = 0;
    struct spi_message msg;
    struct spi_transfer xfer = { 0 };
    unsigned char rx_buf[2] = { 0 };
        
    xfer.tx_buf = NULL;
    xfer.rx_buf = rx_buf;
    xfer.len = 2;

    spi_message_init(&msg);                       /* 初始化spi_message */
    spi_message_add_tail(&xfer, &msg);            /* 添加到传输队列 */
    status = spi_sync(tlc5615_spi, &msg);         /* 同步发送 */

    
    pr_info("tlc5615_spi_read status %d\n", status);

    pr_info("%x %x\n", rx_buf[0], rx_buf[1]);

    return status;
}

static int tlc5615_spi_write(int val)
{

#if 1 // 8bit看作一个数据
    int status = 0;
    struct spi_message msg;
    struct spi_transfer xfer = { 0 };
    unsigned char tx_buf[2] = { 0 };
    
    unsigned char rx_buf[2] = { 0 };
    
    pr_info("spi val %d\n", val);
    //左移两位构成16位
    val = val << 2;
    val = val & 0xffff;
    tx_buf[0] = (val >> 8) & 0xff;
    tx_buf[1] = val & 0xff;
        
#if 1
    xfer.tx_buf = tx_buf;
    xfer.rx_buf = rx_buf;
    // xfer.bits_per_word = 16;   /* 设置成16bit算一次完整传输,默认是8bit为1次 */
    xfer.len = 2;

    spi_message_init(&msg);                       /* 初始化spi_message */
    spi_message_add_tail(&xfer, &msg);            /* 添加到传输队列 */
    status = spi_sync(tlc5615_spi, &msg);         /* 同步发送 */
#else
    status = spi_write(tlc5615_spi, tx_buf, 2);
#endif

    pr_info("tlc5615_spi_write status %d\n", status);

    pr_info("%x %x\n", rx_buf[0], rx_buf[1]);

    tlc5615_spi_read();

    return status;
#endif

#if 0 // 16bit看作一个数据
    int status = 0;
    struct spi_message msg;
    struct spi_transfer xfer = { 0 };
    short tx_buf[1];

    pr_info("spi val %d\n", val);

    tx_buf[0] = val & 0xffff;

    xfer.tx_buf = tx_buf;
    xfer.bits_per_word = 16;
    xfer.rx_buf = NULL;
    xfer.len = 1;

    spi_message_init(&msg);                       /* 初始化spi_message */
    spi_message_add_tail(&xfer, &msg);            /* 添加到传输队列 */
    status = spi_sync(tlc5615_spi, &msg);         /* 同步发送 */

    pr_info("spi status %d\n", status);

    return status;
#endif
}

static int tlc5615_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{

    return 0;
}

static int tlc5615_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    int ret = 0;
    int val = 0;

    pr_info("tlc5615_write\n");
    
    ret = copy_from_user(&val, buf, size);
    if (ret) {
        pr_err("copy_from_user mem_addr failed\n");
        return -EINVAL;
    }

    ret = tlc5615_spi_write(val);
    if (ret < 0 ) {
        pr_err("tlc5615_spi_write failed\n");
        pr_err("ret = %d\n", ret);
        return -EINVAL;
    }

    return size;
}


static struct file_operations tlc5615_fops = {
        .owner = THIS_MODULE,
        .read = tlc5615_read,
        .write = tlc5615_write,
};


/** 设备树参考
 * 	spi_master@f00 {
 *		#address-cells = <1>;
 *		#size-cells = <0>;
 *		compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
 *      cs-gpios = <&gpio1 0 0>, <&gpio1 1 0>;
 *		reg = <0xf00 0x20>;
 *		interrupts = <2 13 0 2 14 0>;
 *		interrupt-parent = <&mpc5200_pic>;
 *
 *      // CPOL = 0, CPHA = 0, SPI模式1, cs低电平有效
 *		spi_dev0@0 {
 *			compatible = "micrel,ks8995m";
 *			spi-max-frequency = <1000000>;
 *			reg = <0>;  //第0个 cs对应<&gpio1 0 0>
 *		}; 
 *
 *      // CPOL = 0, CPHA = 1, SPI模式2, cs高电平有效
 *		spi_dev1@1 {
 *			compatible = "ti,tlv320aic26";
 *			spi-max-frequency = <100000>;
 *			reg = <1>; //第一个 cs对应<&gpio1 1 0>
 *          spi-cpha;
 *          spi-cs-high;
 *		};
 *	};
*/

static int tlc5615_dac_probe(struct spi_device *spi)
{
    int ret = 0;
    pr_info("tlc5615_dac_probe\n");

    /* 保存spi */
    tlc5615_spi = spi;

// 参考Documentation\devicetree\bindings\spi\spi-bus.txt
#if 0
    int spi_cs_pin = 0;
    /*获取 oled 的 D/C 控制引脚并设置为输出，默认高电平*/
    spi_cs_pin = of_get_named_gpio(oled_device_node, "d_c_control_pin", 0);
    gpio_direction_output(spi_cs_pin, 1);
    /*初始化spi, */
    // tlc5615_spi = spi;
    /* 在设备树中配置 */
    tlc5615_spi->mode = SPI_MODE_0;
    tlc5615_spi->max_speed_hz = 2000000;
    spi_setup(tlc5615_spi);
#endif
    
    alloc_chrdev_region(&tlc5615_devid, 0, 1, "tlc5615");
    tlc5615_major = MAJOR(tlc5615_devid);
    tlc5615_minor = MINOR(tlc5615_devid);

    cdev_init(&tlc5615_cdev, &tlc5615_fops);
    cdev_add(&tlc5615_cdev, tlc5615_devid, 1);

    tlc5615_class = class_create(THIS_MODULE, "tlc5615");
    if (IS_ERR(tlc5615_class)) {
        dev_err(&spi->dev, "create class failed\n");
        ret = PTR_ERR(tlc5615_class);
        return -ret;
    }

    tlc5615_device = device_create(tlc5615_class, NULL, tlc5615_devid, NULL, "tlc5615");
    if (IS_ERR(tlc5615_device)) {
         dev_err(&spi->dev, "create device failed\n");
         ret = PTR_ERR(tlc5615_device);
        return -ret;
    }

    return 0;
}

/*
 * 设备被移除了，或者驱动被卸载了，全部要释放，释放资源的操作就放在该函数中
 */
static int tlc5615_dac_remove(struct spi_device *device)
{
    /* 注销类、以及类设备 */
    device_destroy(tlc5615_class, tlc5615_devid);
    class_destroy(tlc5615_class);

    /* 删除设备，卸载注册的设备编号 */
    cdev_del(&tlc5615_cdev);
    unregister_chrdev_region(tlc5615_devid, 1);
    
    return 0;
}

static const struct of_device_id tlc5615_dt_match[] = {
    { .compatible = "texas,tlc5615", },
    { /* END OF LIST */ },
};

static const struct spi_device_id tlc5615_id_table[] = {
    { "tlc5615", 0 },
    { /* END OF LIST */ }
};

/*
 * spi驱动入口函数
*/
static struct spi_driver tlc5615_dac_driver = {
    .driver = {
            .name = "tlc5615_dac",  
            .of_match_table = tlc5615_dt_match,
            .owner = THIS_MODULE,
    },
    .probe = tlc5615_dac_probe,
    .remove = tlc5615_dac_remove,
    .id_table	= tlc5615_id_table,
};


/*
 *init入口函数
*/
static int tlc5615dac_drv_init(void)
{
    spi_register_driver(&tlc5615_dac_driver);  /* 将spi_driver注册到系统中去 */
    printk(KERN_INFO "tl5615_driver spi_driver was added into the system.\n");
    return 0;
}

/*
 * exit出口函数
 */
static void tlc5615dac_drv_exit(void)
{
    spi_unregister_driver(&tlc5615_dac_driver);
    printk(KERN_INFO "tl5615_driver spi_driver was deleted from the system.\n");
    return ;
}


module_init(tlc5615dac_drv_init);
module_exit(tlc5615dac_drv_exit);
MODULE_AUTHOR("huang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("spi driver");


